﻿using SharpDX.Direct3D11;
using System.Windows.Forms;
using SharpDX;
using SharpDX.D3DCompiler;
using SharpDX.DXGI;
using SharpDX.Windows;
using Device = SharpDX.Direct3D11.Device;
using Resource = SharpDX.Direct3D11.Resource;
using System.Runtime.InteropServices;
using SharpDX.Direct3D;

namespace Engine
{
    public class TestSprite : System.IDisposable
    {
        ShaderConstants constants;
        Buffer constantsBuffer;

        EffectContainer EEEM;
        MeshContainer MMesh;
        TextureContainer TexCont;
        //_3 — half screen
        
        public int OcclRequest = -1;

        public DVector3 Position;

        #region IDisposable
        ~TestSprite()
        {
            Dispose();
        }
        public void Dispose()
        {
            constantsBuffer.Dispose();
            MMesh.Dispose();
            EEEM.Dispose();
         }
        #endregion

        public TestSprite(Device device, DVector3 Position)
        {
            this.Position = Position;
            MMesh = ContentManager.LoadMesh("Content/Models/BaseSprite.mesh");
            EEEM = ContentManager.LoadEffect("Content/Shaders/BaseSprite");
            TexCont = ContentManager.LoadTexture2D("Content/Textures/Particl");
            // Подготовка константного буффера
            BufferDescription bd = new BufferDescription();
            bd.SizeInBytes = Marshal.SizeOf(typeof(ShaderConstants));
            bd.Usage = ResourceUsage.Dynamic;
            bd.BindFlags = BindFlags.ConstantBuffer;
            bd.CpuAccessFlags = CpuAccessFlags.Write;
            bd.OptionFlags = ResourceOptionFlags.None;
            bd.StructureByteStride = 0;

            constantsBuffer = new Buffer(device, bd);
            constants = new ShaderConstants();
        }

        public void Render(Device device, EEDCamera Camera)
        {
            ShaderResourceView SRV = null; int Index = -1;
            DrawHelper.GetOcclusionTestResult(OcclRequest, out SRV, out Index);

            device.ImmediateContext.InputAssembler.InputLayout = EEEM.layout;
            device.ImmediateContext.InputAssembler.PrimitiveTopology = PrimitiveTopology.TriangleList;
            device.ImmediateContext.InputAssembler.SetVertexBuffers(0, MMesh.binding);
            device.ImmediateContext.InputAssembler.SetIndexBuffer(MMesh.Indices, Format.R32_UInt, 0);

            EEEM.renderTechniques[0].GetPassByIndex(0).Apply(device.ImmediateContext);

            device.ImmediateContext.PixelShader.SetShaderResource(0, TexCont.TextureResource);
            device.ImmediateContext.PixelShader.SetSampler(0, DrawHelper.SamplAnsWrapMip);

            device.ImmediateContext.PixelShader.SetShaderResource(1, SRV);
            device.ImmediateContext.VertexShader.SetShaderResource(1, SRV);

            constants.OcclIndex = new Vector4(((float)Index) / DrawHelper.OcclPixelInTex, 0, 0, 0);

            Matrix Transform = Conversion.ToMatrix(DMatrix.CreateScale(20) * DMatrix.CreateTranslation(Position) * DMatrix.CreateTranslation(-Camera.position));

            constants.World = Matrix.Transpose(Transform);
            constants.WVP = Matrix.Transpose(Transform * Camera.viewProjectionMatrix);
            constants.InvertMat = Matrix.Transpose(Camera.invertViewMatrix);

            var dataBox = ModelViewer.Program.device.ImmediateContext.MapSubresource(constantsBuffer, 0, MapMode.WriteDiscard, SharpDX.Direct3D11.MapFlags.None);
            Utilities.Write(dataBox.DataPointer, ref constants);
            ModelViewer.Program.device.ImmediateContext.UnmapSubresource(constantsBuffer, 0);

            //Константный буффер передается шейдерам
            device.ImmediateContext.VertexShader.SetConstantBuffer(0, constantsBuffer);
            device.ImmediateContext.PixelShader.SetConstantBuffer(0, constantsBuffer);

            device.ImmediateContext.DrawIndexed(MMesh.FaceCount*3, 0, 0);
            
        }

        public void OcclusionRequest()
        {
            OcclRequest = DrawHelper.OcclusionRequest(Position);
        }
        
        private struct ShaderConstants
        {
            public Matrix World;
            public Matrix WVP;
            public Matrix InvertMat;
            public Vector4 OcclIndex;
        }

    }
}
